﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using System.Web;
using System.Linq.Dynamic;
using System.Linq.Dynamic.Core;

public static class Extensions
{
    /// <summary>
    /// 转换为HashSet集合
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"></param>
    /// <returns></returns>
    public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source) {
        if (source == null) {
            throw new ArgumentNullException(nameof(source));
        }

        return new HashSet<T>(source);
    }

    /// <summary>
    /// 转换为HashSet集合
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"></param>
    /// <returns></returns>
    public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer) {
        if (source == null) {
            throw new ArgumentNullException(nameof(source));
        }

        if (comparer == null) {
            throw new ArgumentNullException(nameof(comparer));
        }

        return new HashSet<T>(source, comparer);
    }

    /// <summary>
    /// 集合拼接为字符串
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"></param>
    /// <param name="separator"></param>
    /// <returns></returns>
    public static string Join<T>(this IEnumerable<T> source, string separator) {
        if (separator == null) {
            throw new ArgumentNullException(nameof(separator));
        }

        return string.Join<T>(separator, source);
    }

    /// <summary>
    /// 循环集合元素
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="action"></param>
    public static void ForEach_<T>(this IEnumerable<T> list, Action<T> action) {
        if (action == null) {
            throw new ArgumentNullException(nameof(action));
        }

        foreach (var item in list) {
            action(item);
        }
    }

    /// <summary>
    /// 转换只读集合
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <returns></returns>
    public static IReadOnlyList<T> ToReadOnly<T>(this IEnumerable<T> list) {
        if (list == null) {
            throw new ArgumentNullException(nameof(list));
        }

        return list.ToList().AsReadOnly();
    }

    /// <summary>
    /// 判断集合是否为null或者空
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <returns></returns>
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> list) {
        return list == null || !list.Any();
    }

    /// <summary>
    /// 判断集合是否存在重复元素
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="keyComparer"></param>
    /// <returns></returns>
    public static bool HasRepeat<T>(this IEnumerable<T> list, IEqualityComparer<T> keyComparer = null) {
        if (list == null) {
            throw new ArgumentNullException(nameof(list));
        }
        if (keyComparer == null)
            return list.GroupBy(r => r).Any(g => g.Count() > 1);
        else
            return list.GroupBy(r => r, keyComparer).Any(g => g.Count() > 1);
    }

    /// <summary>
    /// 判断集合中是否存在属性相等的元素
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="selectProperty"></param>
    /// <param name="keyComparer"></param>
    /// <returns></returns>
    public static bool HasRepeat<T>(this IEnumerable<T> list, Func<T, object> selectProperty, IEqualityComparer<object> keyComparer = null) {
        if (list == null) {
            throw new ArgumentNullException(nameof(list));
        }

        if (selectProperty == null) {
            throw new ArgumentNullException(nameof(selectProperty));
        }

        if (keyComparer == null)
            return list.GroupBy(selectProperty).Any(g => g.Count() > 1);
        else
            return list.GroupBy(selectProperty, keyComparer).Any(g => g.Count() > 1);
    }


    public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> list, bool condition, Func<T, bool> where) {
        if (list == null) {
            throw new ArgumentNullException(nameof(list));
        }

        if (where == null) {
            throw new ArgumentNullException(nameof(where));
        }

        if (condition)
            return list.Where(where);
        return list;
    }

    public static IQueryable<T> WhereIf<T>(this IQueryable<T> list, bool condition, Expression<Func<T, bool>> where) {
        if (list == null) {
            throw new ArgumentNullException(nameof(list));
        }

        if (where == null) {
            throw new ArgumentNullException(nameof(where));
        }

        if (condition)
            return list.Where(where);
        return list;
    }

    /// <summary>
    /// 按字段名称进行排序
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="query"></param>
    /// <param name="field">排序字段,多个使用逗号分隔,如"id,sort"</param>
    /// <param name="order">排序方式,多个排序方式用 逗号分隔如:"asc,desc,asc",与field字段顺序对应,没有的默认为asc</param>
    /// <returns></returns>
    public static IQueryable<T> Sorting<T>(this IQueryable<T> query, string field, string order) {
        if (query == null) {
            throw new ArgumentNullException(nameof(query));
        }
        if (field.IsNullOrWhiteSpace()) {
            throw new ArgumentNullException(nameof(field));
        }

        var orders = order?.Split(',');
        var fields = field.Split(',');
        List<string> orderString = new List<string>();
        for (int i = 0; i < fields.Length; i++) {
            var o = orders != null && orders.Length - 1 < i ? "asc" : orders[i].Trim();
            if (!o.EqualsIgnoreCase("asc") && !o.EqualsIgnoreCase("desc"))
                o = "asc";
            orderString.Add($"{fields[i].Trim()} {o}");
        }
        query = query.OrderBy(orderString.Join(","));
        return query;
    }


    /// <summary>
    /// 分页查询
    /// </summary>
    /// <param name="query">查询源</param>
    /// <param name="pageIndex">当前页,索引从1开始</param>
    /// <param name="pageSize">每页大小</param>
    /// <returns></returns>
    public static IQueryable<T> Paging<T>(this IQueryable<T> query, int pageIndex, int pageSize) {
        if (query == null) {
            throw new ArgumentNullException(nameof(query));
        }

        return
            query
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize);
    }

    /// <summary>
    /// 是否为null或者空字符串
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static bool IsNullOrWhiteSpace(this string str) {
        return string.IsNullOrWhiteSpace(str);
    }

    /// <summary>
    /// 字符串比较 忽略大小写
    /// </summary>
    /// <param name="source"></param>
    /// <param name="target"></param>
    /// <returns></returns>
    public static bool EqualsIgnoreCase(this string source, string target) {
        return source.Equals(target, StringComparison.OrdinalIgnoreCase);
    }

    /// <summary>
    /// 字符串分割为数组
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="str"></param>
    /// <param name="separators"></param>
    /// <returns></returns>
    public static List<T> Split<T>(this string str, params string[] separators) where T : struct {
        if (string.IsNullOrWhiteSpace(str))
            return new List<T>();
        return
            str
            .Split(separators, StringSplitOptions.RemoveEmptyEntries)
            .Select(ConvertTo<T>).ToList();
    }

    /// <summary>
    /// 字符串分割为数组,跳过不能转换的异常数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="str"></param>
    /// <param name="separators"></param>
    /// <returns></returns>
    public static List<T> SplitSkipError<T>(this string str, params string[] separators) where T : struct {
        if (string.IsNullOrWhiteSpace(str))
            return new List<T>();
        var query =
            str
            .Split(separators, StringSplitOptions.RemoveEmptyEntries);

        List<T> result = new List<T>();
        foreach (var item in query) {
            try {
                result.Add(item.ConvertTo<T>());
            }
            catch { }
        }
        return result;
    }

    public static bool Contains(this string source, string value, StringComparison stringComparison) {
        if (source == null || value == null) { return false; }
        if (value == "") { return true; }
        return (source.IndexOf(value, stringComparison) >= 0);
    }

    /// <summary>
    /// 字符串截取,null时,返回"",不足长度时,返回字符串本身
    /// </summary>
    /// <param name="str"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    public static string SubStringIfTooLong(this string str, int length, string suffix = "...") {
        if (string.IsNullOrWhiteSpace(str))
            return "";
        var str1 = str.Trim();
        if (str1.Length <= length)
            return str1.Trim();

        return str1.Substring(0, length) + suffix;
    }

    /// <summary>
    /// 字符串替换,忽略大小写,使用的是正则,注意正则中的特殊字符
    /// </summary>
    /// <param name="str"></param>
    /// <param name="pattern"></param>
    /// <param name="replaceString"></param>
    /// <returns></returns>
    public static string ReplaceIgnoreCase(this string str, string pattern, string replaceString) {
        return Regex.Replace(str, pattern, replaceString, RegexOptions.IgnoreCase);
    }

    /// <summary>
    /// 类型转换
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T ConvertTo<T>(this object value) where T : struct {
        if (value == null)
            return default(T);

        if (value is T)
            return (T)value;

        var destinationType = typeof(T);
        var sourceType = value.GetType();
        if (destinationType == typeof(bool) || destinationType == typeof(bool?))
            value = Convert.ToBoolean(value);

        TypeConverter destinationConverter = TypeDescriptor.GetConverter(destinationType);
        TypeConverter sourceConverter = TypeDescriptor.GetConverter(sourceType);
        if (destinationConverter != null && destinationConverter.CanConvertFrom(value.GetType()))
            return (T)destinationConverter.ConvertFrom(value);
        if (sourceConverter != null && sourceConverter.CanConvertTo(destinationType))
            return (T)sourceConverter.ConvertTo(value, destinationType);
        if (destinationType.IsEnum && value is int)
            return (T)Enum.ToObject(destinationType, (int)value);
        if (!destinationType.IsInstanceOfType(value))
            return (T)Convert.ChangeType(value, destinationType);
        return (T)value;
    }


}
